package com.cicadasmall.builder.core;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.ConstVal;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.cicadasmall.builder.core.callback.ICallBack;
import com.cicadasmall.builder.core.config.MyGlobalConfig;
import com.cicadasmall.builder.core.constant.MyConstVal;
import com.cicadasmall.builder.core.engine.MyVelocityTemplateEngine;
import com.cicadasmall.builder.core.config.MyPackageConfig;
import com.cicadasmall.builder.core.po.MyTableInfo;
import lombok.AccessLevel;
import lombok.Setter;
import org.springframework.beans.BeanUtils;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Generator
 *
 * @author Jin
 */
public class Generator extends AutoGenerator {

    @Setter(value = AccessLevel.NONE)
    protected ICallBack callBack;

    @Override
    public void execute() {
        //设置自定义模板引擎
        setTemplateEngine(new MyVelocityTemplateEngine());
        super.execute();
        //执行回调函数
        if (null != callBack)
            callBack.run();
    }


    public MyTableInfo copyToMyTableInfo(TableInfo tableInfo) {
        MyTableInfo myTableInfo = new MyTableInfo();
        BeanUtils.copyProperties(tableInfo, myTableInfo);
        //设置DTO文件名
        myTableInfo.setInputDTOName(String.format(MyConstVal.INPUT_DTO, tableInfo.getEntityName()));
        myTableInfo.setUpdateDTOName(String.format(MyConstVal.UPDATE_DTO, tableInfo.getEntityName()));
        myTableInfo.setQueryDTOName(String.format(MyConstVal.QUERY_DTO, tableInfo.getEntityName()));
        //设置VO文件名
        myTableInfo.setEntityVOName(tableInfo.getEntityName() + MyConstVal.VO);
        //设置Wrapper文件名
        myTableInfo.setWrapperName(tableInfo.getEntityName() + MyConstVal.WRAPPER);
        //设置Entity文件名为DO
        myTableInfo.setEntityName(tableInfo.getEntityName() + MyConstVal.DO);
        return myTableInfo;
    }

    @Override
    protected ConfigBuilder pretreatmentConfigBuilder(ConfigBuilder config) {
        ConfigBuilder configBuilder = super.pretreatmentConfigBuilder(config);
        PackageConfig packageConfig = this.getPackageInfo();
        Map<String, String> packageInfo = config.getPackageInfo();
        Map<String, String> pathInfo = config.getPathInfo();
        List<TableInfo> tableInfoList = config.getTableInfoList();
        MyGlobalConfig globalConfig = (MyGlobalConfig) this.getGlobalConfig();
        //增加自定义属性
        config.setTableInfoList(tableInfoList.stream().map(this::copyToMyTableInfo).collect(Collectors.toList()));

        //DTO
        String inputDTO = String.format(MyConstVal.INPUT_DTO, "");
        String updateDTO = String.format(MyConstVal.UPDATE_DTO, "");
        String queryDTO = String.format(MyConstVal.QUERY_DTO, "");

        MyPackageConfig myPackageConfig = (MyPackageConfig) packageConfig;

        //===============================================================
        // 包设置
        //===============================================================

        //DTO包设置
        packageInfo.put(inputDTO, joinPackage(packageConfig.getParent(), myPackageConfig.getDto()));
        packageInfo.put(updateDTO, joinPackage(packageConfig.getParent(), myPackageConfig.getDto()));
        packageInfo.put(queryDTO, joinPackage(packageConfig.getParent(), myPackageConfig.getDto()));
        //VO包设置
        packageInfo.put(MyConstVal.VO, joinPackage(packageConfig.getParent(), myPackageConfig.getVo()));
        //WRAPPER包设置
        packageInfo.put(MyConstVal.WRAPPER, joinPackage(packageConfig.getParent(), myPackageConfig.getWrapper()));

        //===============================================================
        // 路径设置
        //===============================================================

        String parent = packageConfig.getParent() + StringPool.DOT + "data";

        //===============================================================
        // do
        //===============================================================
        packageInfo.put(ConstVal.ENTITY, (parent + StringPool.DOT + MyConstVal.DO.toLowerCase()));
        pathInfo.put(ConstVal.ENTITY_PATH, joinPath(globalConfig.getDoFileOutputDir(), packageInfo.get(ConstVal.ENTITY)));

        //===============================================================
        // dao
        //===============================================================


        packageInfo.put(ConstVal.XML, (parent + StringPool.DOT + packageConfig.getXml()));
        packageInfo.put(ConstVal.MAPPER, (parent + StringPool.DOT + packageConfig.getMapper()));
        packageInfo.put(ConstVal.ENTITY, (parent + StringPool.DOT + packageConfig.getEntity()));

        pathInfo.put(ConstVal.XML_PATH, joinPath(globalConfig.getDaoFileOutputDir(), packageInfo.get(ConstVal.XML)));
        pathInfo.put(ConstVal.MAPPER_PATH, joinPath(globalConfig.getDaoFileOutputDir(), packageInfo.get(ConstVal.MAPPER)));


        //===============================================================
        // logic
        //===============================================================


        pathInfo.put(ConstVal.CONTROLLER_PATH, joinPath(globalConfig.getLogicFileOutputDir(), packageInfo.get(ConstVal.CONTROLLER)));

        //Service
        setPathInfo(pathInfo, MyConstVal.TEMPLATE_SERVICE, globalConfig.getLogicFileOutputDir(), MyConstVal.SERVICE_PATH, MyConstVal.SERVICE);
        setPathInfo(pathInfo, MyConstVal.TEMPLATE_SERVICE_IMPL, globalConfig.getLogicFileOutputDir(), MyConstVal.SERVICE_IMPL_PATH, MyConstVal.SERVICE_IMPL);

        //DTO
        setPathInfo(pathInfo, MyConstVal.TEMPLATE_INPUT_DTO, globalConfig.getLogicFileOutputDir(), MyConstVal.DTO_PATH, inputDTO);
        setPathInfo(pathInfo, MyConstVal.TEMPLATE_QUERY_DTO, globalConfig.getLogicFileOutputDir(), MyConstVal.DTO_PATH, updateDTO);
        setPathInfo(pathInfo, MyConstVal.TEMPLATE_UPDATE_DTO, globalConfig.getLogicFileOutputDir(), MyConstVal.DTO_PATH, queryDTO);
        //VO
        setPathInfo(pathInfo, MyConstVal.TEMPLATE_VO, globalConfig.getLogicFileOutputDir(), MyConstVal.VO_PATH, MyConstVal.VO);

        //WRAPPER路径设置
        setPathInfo(pathInfo, MyConstVal.TEMPLATE_WRAPPER, globalConfig.getLogicFileOutputDir(), MyConstVal.WRAPPER_PATH, MyConstVal.WRAPPER);

        return configBuilder;
    }


    private String joinPackage(String parent, String subPackage) {
        if (StringUtils.isBlank(parent)) {
            return subPackage;
        }
        return parent + StringPool.DOT + subPackage;
    }

    private void setPathInfo(Map<String, String> pathInfo, String template, String outputDir, String path, String module) {
        if (StringUtils.isNotBlank(template)) {
            Map<String, String> packageInfo = getConfig().getPackageInfo();
            pathInfo.put(path, joinPath(outputDir, packageInfo.get(module)));
        }
    }

    private String joinPath(String parentDir, String packageName) {
        if (!StringUtils.endsWith(parentDir, File.separator)) {
            parentDir += File.separator;
        }
        packageName = packageName.replaceAll("\\.", StringPool.BACK_SLASH + File.separator);
        return parentDir + packageName;
    }
}

